48 创建序列和数据框
48.1 引言 Pandas数据结构在金融分析中的核心地位
Pandas是Python数据分析的核心库,建立在NumPy之上,提供了两种专为数据分析和处理设计的数据结构:
理论背景:从NumPy到Pandas的演进
NumPy数组提供了高效的数值计算能力,但在数据分析中存在三个关键限制: 1. 缺乏标签:NumPy数组只能通过整数位置访问,无法使用有意义的标签(如股票代码、日期) 2. 数据类型单一:NumPy数组的所有元素必须是相同类型 3. 缺失值处理:NumPy使用NaN表示缺失值,但处理不够灵活
Pandas通过Series和DataFrame这两种数据结构完美解决了这些问题,使其成为金融数据分析的理想工具。
Pandas两种核心数据结构:
| 特性 | Series | DataFrame |
|---|---|---|
| 维度 | 一维 | 二维 |
| 类比 | 带标签的数组 | 带标签的表格/Excel工作表 |
| 索引 | 必须有索引 | 必须有行索引,列名是另一种索引 |
| 金融应用 | 单只股票的价格序列 | 多只股票的多指标数据表 |
48.2 创建Series对象
Series是Pandas的一维数据结构,可以理解为”带标签的数组”。在金融应用中,Series非常适合存储单只股票的价格序列、单只股票的交易量序列、或某一天的多个股票价格等一维数据。
平台任务解答代码
以下代码与教学平台任务要求完全一致:
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
#任务一
import numpy as np
import pandas as pd # 导入Pandas数据分析库
value_guotai = np.array([1.5284,1.4596,1.3745,1.4034,1.3935,1.39,1.412,1.4164]) #国泰金鑫股票基金2024年8月1日至8日净值数据的数组
date = np.array(["2024-08-01","2024-08-02","2024-08-05","2024-08-06","2024-08-07","2024-08-08","2024-08-09","2024-08-12"]) #交易日数组
series_guotai = pd.Series(data=value_guotai,index=date) #创建序列
print(type(series_guotai)) #查看变量的数据结构
data=[1.4596,1.001,0.897,2.051,1.7385];index=["国泰金鑫","中海医疗","华夏优势","富国城镇","上投摩根"] #创建8月2日基金净值的数组
value_0403 = pd.Series(data,index) # 创建Series序列value_0403
print(type(value_0403)) # 输出数据类型
#任务二
import numpy as np
import pandas as pd # 导入Pandas数据分析库
date = np.array(["2024-08-01","2024-08-02","2024-08-05","2024-08-06","2024-08-07","2024-08-08","2024-08-09","2024-08-12"]) #交易日数组
name = np.array(["国泰金鑫","中海医疗","华夏优势","富国城镇","上投摩根"]) #基金名称的数组并且用基金简称
data_3fund_array = np.array([[1.01,0.8918,2.038],[0.995,0.8833,2.025],[1.002,0.8735,2.032]]) #3只基金在2024年8月8日至12日净值的数组
data_3fund = pd.DataFrame(data=data_3fund_array,index=date[5:],columns=name[1:4]) #转成一个数据框
print(type(data_3fund)) # 输出数据类型
#任务三
import numpy as np
import pandas as pd # 导入Pandas数据分析库
date = np.array(["2024-08-01","2024-08-02","2024-08-05","2024-08-06","2024-08-07","2024-08-08","2024-08-09","2024-08-12"]) #交易日数组
name = np.array(["国泰金鑫","中海医疗","华夏优势","富国城镇","上投摩根"]) # 创建NumPy数组name
# 创建NumPy数组value_total
value_total = np.array([[1.5284,0.991,0.9122,2.069,1.7742],[1.4596,1.001,0.897,2.051,1.7385],[1.3745,1,0.8786,2.023,1.6843],[1.4034,1.013,0.8944,2.027,1.6917],
[1.3935,1.007,0.8944,2.031,1.6957],[1.39,1.01,0.8918,2.038,1.6955],[1.412,0.995,0.8833,2.025,1.6938],[1.6938,1.002,0.8735,2.032,1.6899]]) #创建数组
data_total = pd.DataFrame(data=value_total,index=date,columns=name) #转为数据框
print(data_total) # 输出数据数据
#任务四
import numpy as np
import pandas as pd # 导入Pandas数据分析库
value_guotai = np.array([1.5284,1.4596,1.3745,1.4034,1.3935,1.39,1.412,1.4164]) #国泰金鑫股票基金2024年8月1日至8日净值数据的数组
date = np.array(["2024-08-01","2024-08-02","2024-08-05","2024-08-06","2024-08-07","2024-08-08","2024-08-09","2024-08-12"]) #交易日数组
series_guotai = pd.Series(data=value_guotai,index=date) # 创建Series序列series_guotai
data=[1.4596,1.001,0.897,2.051,1.7385];index=["国泰金鑫","中海医疗","华夏优势","富国城镇","上投摩根"] #创建8月2日基金净值的数组
value_0403 = pd.Series(data,index) # 创建Series序列value_0403
name = np.array(["国泰金鑫","中海医疗","华夏优势","富国城镇","上投摩根"]) #基金名称的数组并且用基金简称
data_3fund_array = np.array([[1.01,0.8918,2.038],[0.995,0.8833,2.025],[1.002,0.8735,2.032]])#3只基金在2024年8月8日至12日净值的数组
data_3fund = pd.DataFrame(data=data_3fund_array,index=date[5:],columns=name[1:4]) # 创建数据框data_3fund
list_guotai = list(series_guotai)#国泰金鑫8与1日到12日净值数据的序列转为列表
array_0403 = np.array(value_0403) #8月2日5只基金净值的序列转为数组
array_3fund = data_3fund.values #8月8日到12日3只基金净值的数据框变为数组
print(array_3fund) # 输出基金数据# =============================================================================
# 题目:创建Pandas Series对象
# =============================================================================
# 本任务演示三种不同的Series创建方法,适用于不同的数据来源场景
# ==================== 导入必要的库 ====================
# pandas:Python数据分析的核心库
import pandas as pd
# numpy:Python科学计算的基础库,pandas依赖numpy
import numpy as np
# ==================== 方法1:从Python列表创建Series ====================
# 场景:当你有一系列数值数据需要存储为Series时
# 列表[10, 20, 30, 40, 50]包含5个整数元素
# pd.Series()函数将列表转换为Series对象
# Series会自动为这些元素创建默认的整数索引(0, 1, 2, 3, 4)
s1 = pd.Series([10, 20, 30, 40, 50])
# 结果:一个Series对象,值为[10, 20, 30, 40, 50],索引为[0, 1, 2, 3, 4]
# ==================== 方法2:从字典创建Series ====================
# 场景:当你有键值对数据,且键本身就是有意义的标签时
# 字典的键(股票名称)会成为Series的索引
# 字典的值(股价)会成为Series的值
# name参数指定Series的名称,用于标识这个Series
s2 = pd.Series({
'贵州茅台': 1850, # 键'贵州茅台',值1850(股价)
'五粮液': 220, # 键'五粮液',值220(股价)
'招商银行': 45 # 键'招商银行',值45(股价)
}, name='股价') # 设置Series名称为'股价'
# 结果:一个Series对象,索引为['贵州茅台', '五粮液', '招商银行']
# 值为[1850, 220, 45],名称为'股价'
# ==================== 方法3:从NumPy数组创建Series ====================
# 场景:当你有数值计算的结果需要转换为Series时
# np.random.randn(5)生成5个标准正态分布的随机数(均值0,标准差1)
# 这些随机数可以用于模拟股票收益率等金融数据
s3 = pd.Series(np.random.randn(5))
# 结果:一个Series对象,包含5个随机数,索引为默认的[0, 1, 2, 3, 4]
# ==================== 打印输出Series对象 ====================
print('Series 1 (从列表创建):')
print(s1) # 输出Series的完整表示:索引、值、数据类型
print('\nSeries 2 (从字典创建):')
print(s2) # 输出带名称的Series
print(f'索引: {s2.index.tolist()}') # .index获取索引对象,.tolist()转换为Python列表
# 输出:['贵州茅台', '五粮液', '招商银行']代码深度解析:
- Series的组成结构:
- 索引(index):每个数据点的标签,用于定位和访问数据
- 值(values):实际存储的数据
- 名称(name):Series对象的标识(可选)
- 数据类型(dtype):值的类型(如int64、float64、object等)
- 从字典创建的优势:
- 索引自动设置为字典的键,无需手动指定
- 适合表示有标签的数据(如股票名称到价格的映射)
- 比从列表创建后设置索引更简洁
- Series与NumPy数组的关系:
- Series基于NumPy数组构建
- Series.values返回底层的NumPy数组
- Series比NumPy数组多了索引功能
48.3 创建DataFrame
DataFrame是Pandas的二维数据结构,类似于Excel表格或SQL数据库的表。在金融分析中,DataFrame是最常用的数据结构,用于存储和分析多只股票的多指标数据。
# =============================================================================
# 题目:创建Pandas DataFrame对象
# =============================================================================
# 本任务演示如何从字典创建DataFrame来存储股票数据
# ==================== 从字典创建DataFrame ====================
# 场景:当你的数据是以字典形式组织时,每个键是一个列名,每个值是列数据
# 字典的键('股票代码', '股票名称', '股价', '涨跌幅')将成为DataFrame的列名
# 字典的值都是列表,这些列表的长度必须相同(这里都是3个元素)
data = {
'股票代码': ['600519.SH', '000858.SZ', '600036.SH'], # 第一列:股票代码
'股票名称': ['贵州茅台', '五粮液', '招商银行'], # 第二列:公司名称
'股价': [1850.0, 220.5, 45.2], # 第三列:股价(浮点数)
'涨跌幅': [0.05, -0.02, 0.03] # 第四列:涨跌幅(浮点数)
}
# pd.DataFrame()函数将字典转换为DataFrame对象
# Pandas会自动:
# 1. 使用字典的键作为列名
# 2. 对齐所有列表的数据(创建3行×4列的表格)
# 3. 自动生成默认的行索引(0, 1, 2)
df = pd.DataFrame(data)
# ==================== 打印DataFrame的基本信息 ====================
print('DataFrame内容:')
print(df)
# 输出格式:
# 股票代码 股票名称 股价 涨跌幅
# 0 600519.SH 贵州茅台 1850.0 0.05
# 1 000858.SZ 五粮液 220.5 -0.02
# 2 600036.SH 招商银行 45.2 0.03
# 左侧的0,1,2是行索引,顶部是列名
# ==================== 查看DataFrame的属性 ====================
print(f'\nDataFrame形状: {df.shape}') # shape属性返回(行数, 列数)
# 输出:(3, 4) - 表示3行4列的表格
print(f'列名列表: {df.columns.tolist()}') # columns获取所有列名,tolist()转换为列表
# 输出:['股票代码', '股票名称', '股价', '涨跌幅']48.4 从NumPy数组创建DataFrame
在科学计算和金融建模中,数据往往以NumPy数组的形式产生(如数值模拟的结果、矩阵运算的结果)。将NumPy数组转换为DataFrame可以添加有意义的标签,使数据更易读和易分析。
# =============================================================================
# 题目:从NumPy数组创建DataFrame
# =============================================================================
# 本任务演示如何将NumPy数值数组转换为带标签的DataFrame
# ==================== 创建随机NumPy数组 ====================
# np.random.randn(5, 3)生成一个5行×3列的数组
# 5行:5个观测样本(如5个交易日或5只股票)
# 3列:每个样本有3个特征(如开盘价、最高价、最低价)
# 这些数据服从标准正态分布(均值0,标准差1)
arr = np.random.randn(5, 3)
# 结果:一个5×3的NumPy数组,包含随机数值
# ==================== 将NumPy数组转换为DataFrame ====================
# pd.DataFrame()函数可以将NumPy数组转换为DataFrame
# arr参数:要转换的NumPy数组(数据来源)
# columns参数:指定DataFrame的列名(列表形式)
# index参数:指定DataFrame的行标签(列表形式)
df_random = pd.DataFrame(
arr, # 数据来源:5×3的随机数组
columns=['特征1', '特征2', '特征3'], # 列名:为3列分别命名
index=['样本1', '样本2', '样本3', '样本4', '样本5'] # 行标签:为5行分别命名
)
# 结果:一个5×3的DataFrame,行标签为"样本1"到"样本5",列名为"特征1"到"特征3"
# ==================== 打印DataFrame ====================
print('从NumPy数组创建的DataFrame:')
print(df_random)
# 输出格式:
# 特征1 特征2 特征3
# 样本1 随机值1 随机值2 随机值3
# 样本2 随机值1 随机值2 随机值3
# ...(共5行)48.5 从列表的列表创建DataFrame
当数据以嵌套列表的形式组织时(例如从CSV文件读取的数据,或从API获取的JSON数据),也可以直接创建DataFrame。
# =============================================================================
# 题目:从列表的列表创建DataFrame
# =============================================================================
# 本任务演示如何将嵌套列表转换为DataFrame
# ==================== 准备嵌套列表数据 ====================
# 场景:当你有多个记录,每个记录包含多个字段时
# 外层列表包含3个元素(3条股票记录)
# 每个元素是一个列表,包含[名称, 价格, 涨跌幅]三个字段
data_list = [
['贵州茅台', 1850.0, 0.05], # 第1条记录
['五粮液', 220.5, -0.02], # 第2条记录
['招商银行', 45.2, 0.03] # 第3条记录
]
# data_list是一个"列表的列表"结构
# ==================== 从列表的列表创建DataFrame ====================
# pd.DataFrame()函数可以接受嵌套列表作为输入
# data_list参数:数据源(嵌套列表)
# columns参数:指定列名,为每列数据赋予有意义的名称
# - '名称':第一列数据(股票名称)
# - '价格':第二列数据(股价)
# - '涨跌幅':第三列数据(涨跌百分比)
df_from_list = pd.DataFrame(
data_list, # 数据:嵌套列表
columns=['名称', '价格', '涨跌幅'] # 列名:指定3个列的名称
)
# Pandas会自动将嵌套列表的每个子列表对应到一行
# 子列表的第0个元素对应第1列,第1个元素对应第2列,以此类推
# ==================== 打印DataFrame ====================
print('从列表的列表创建的DataFrame:')
print(df_from_list)
# 输出格式:
# 名称 价格 涨跌幅
# 0 贵州茅台 1850.0 0.05
# 1 五粮液 220.5 -0.02
# 2 招商银行 45.2 0.0348.6 设置DataFrame的索引
索引(Index)是Pandas数据结构的重要特性,它为每行数据提供了一个有意义的标识。在金融时间序列分析中,通常将日期设置为索引,以便进行时间序列操作(如按日期切片、重采样等)。
# =============================================================================
# 题目:设置DataFrame的行索引
# =============================================================================
# 本任务演示如何为DataFrame设置有意义的行标签
# ==================== 创建示例DataFrame ====================
# 创建一个简单的DataFrame用于演示
df = pd.DataFrame({
'价格': [10, 20, 30, 40, 50], # 第1列:价格数据
'销量': [100, 200, 150, 300, 250] # 第2列:销量数据
})
# 默认会创建整数索引0, 1, 2, 3, 4
# ==================== 生成日期序列作为索引 ====================
# pd.date_range()函数生成日期序列(DatetimeIndex对象)
# '2024-01-01':起始日期
# periods=5:生成5个日期
# 默认频率是'D'(每天),也可以指定'B'(工作日)、'M'(月)等
dates = pd.date_range('2024-01-01', periods=5)
# 结果:DatetimeIndex(['2024-01-01', '2024-01-02', ..., '2024-01-05'])
# ==================== 将日期设置为DataFrame的索引 ====================
# set_index()方法将某列(或外部数据)设置为行索引
# dates参数:使用前面生成的日期序列作为新索引
# 原来的整数索引(0, 1, 2, 3, 4)会被替换
df_indexed = df.set_index(dates)
# 结果:DataFrame的行索引变成了日期,而不是数字
# ==================== 打印带日期索引的DataFrame ====================
print('带日期索引的DataFrame:')
print(df_indexed)
# 输出格式:
# 价格 销量
# 2024-01-01 10 100
# 2024-01-02 20 200
# 2024-01-03 30 150
# ...(共5行)
# 左侧是日期索引,不再是0, 1, 2...
# ==================== 索引的好处 ====================
# 现在可以使用日期来选择数据,例如:
# df_indexed.loc['2024-01-01'] # 获取特定日期的数据
# df_indexed.loc['2024-01-01':'2024-01-03'] # 获取日期范围的数据
# 这比使用整数位置(如df.iloc[0:3])更直观、更不容易出错